package com.lux.disk.controller;

import cn.hutool.core.date.DateUtil;
import cn.hutool.core.io.FileUtil;
import cn.hutool.core.util.RuntimeUtil;
import cn.hutool.crypto.SecureUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.util.StreamUtils;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.multipart.MultipartHttpServletRequest;
import javax.annotation.PostConstruct;
import javax.servlet.http.HttpServletRequest;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.nio.charset.StandardCharsets;
import java.util.List;

/**
 * @author Lux Sun
 * @date 2021/7/8
 */
@Slf4j
@RestController
@RequestMapping("/disk")
public class DiskController {

    @Value("${file.dir}")
    private String dest;

    @Value("${timeout}")
    private Long timeout;

    @Value("${salt}")
    private String salt;

    @PostConstruct
    private void init() {
        File file = new File(dest);
        if (!file.exists()) {
            file.mkdirs();
        }
    }

    @PostMapping("/save")
    public String saveDisk(HttpServletRequest request, @RequestParam(defaultValue = "-1") String port) throws IOException, InterruptedException {
        String timestamp = request.getHeader("timestamp");
        String sign = request.getHeader("sign");
        if (StringUtils.isBlank(timestamp) || StringUtils.isBlank(sign)) {
            return "传参有误";
        }

        long diffSeconds = DateUtil.currentSeconds() - Long.valueOf(timestamp);
        if (diffSeconds < 0 || diffSeconds > timeout) {
            return "时间过期";
        }

        String checkSign = SecureUtil.md5(salt + timestamp);
        if (!StringUtils.equalsIgnoreCase(checkSign, sign)) {
            return "鉴权失败";
        }

        List<MultipartFile> files = ((MultipartHttpServletRequest) request).getFiles("file");
        MultipartFile multipartFile;
        if (files.size() > 0) {
            multipartFile = files.get(0);
        } else {
            log.error("文件上传失败, 未读取到文件! 请确保 Content-Type 为 multipart/form-data; 并且文件参数的 key 为 file");
            return "Error";
        }

        // 保存文件到本地
        String fileName = multipartFile.getOriginalFilename();
//        String fileName = new String(multipartFile.getOriginalFilename().getBytes("ISO8859-1"), "UTF-8");
        InputStream fileIs = multipartFile.getInputStream();
        if (checkFileExist(fileName)) {
            String[] split = fileName.split("\\.");
            String fileType = "";
            if (split.length > 1) {
                fileType = "." + split[split.length - 1];
                int idx = fileName.lastIndexOf(fileType);
                fileName = new StringBuilder(fileName).delete(idx, fileName.length()).toString();
            }
            fileName += "_" + System.currentTimeMillis() + fileType;
        }
        FileUtil.writeFromStream(fileIs, dest + fileName);

        if (!StringUtils.equals("-1", port)) {
            // 终止旧项目
            String cmds = "lsof -i:" + port + " -t";
            String pid = RuntimeUtil.execForStr(cmds).trim();
            System.out.println("Pid: " + pid);
            if (StringUtils.isNotBlank(pid)) {
                cmds = "kill -9 " + pid;
                String kill = RuntimeUtil.execForStr(cmds);
                System.out.println("Kill: " + kill);
            }
            // 启动项目
            cmds = "java -jar " + fileName;
            File file = FileUtil.file(dest);
            callSh(file, cmds);
        }

        return "Success";
    }

    private void callSh(File tarFile, String cmds) throws InterruptedException, IOException {
        System.out.println(cmds);
        Process process = RuntimeUtil.exec(null, tarFile, cmds);
        int status = process.waitFor();
        if (0 != status) {
            InputStream errorStream = process.getErrorStream();
            String errInfo = StreamUtils.copyToString(errorStream, StandardCharsets.UTF_8);
            System.err.println("Failed to call shell's command and the return status's is: " + status);
            System.err.println("Error Info: " + errInfo);
        }
    }

    private boolean checkFileExist(String fileName) {
        File file = new File(dest + fileName);
        if(!file .exists()) {
            return false;
        }
        return true;
    }

    @GetMapping("/heart")
    public String checkHealth() {
        return "OK";
    }
}